多數程式語言的學習第一步常為瞭解資料型態,畢竟分不清楚資料的型態的話,就不可能對資料做出正確處理或判斷,以比喻來說,買股票時,明知道電子股會漲,但是卻買進保護傘公司的股票,以為保護傘公司是電子科技股,結果是搞生化的!?
多數文章資料都會直接說一句Ruby裡幾乎所有東西都為物件
,造成這點的原因是,Ruby在設計上已經將資料的特性與方法包裝後,組成各種class,所謂的東西
都是指class產生的實體。
BasicObject
為所有常用類別的頂端(但Class
的頂端是Module
),再以duck typing
設計風格,將資料特性分組好,給予我們想要執行的方法包裝好後,再給予一個名字(標籤,常數),就成了許多的新class。
物件即為class的實體化,所以物件本身就包含了特性與方法,所以才可以操作物件,因此Ruby內所有東西都為物件
。
不是所有物件導向設計的程式語言都是如此設計,但Ruby這樣設計,且物件導向的很徹底。
wiki--物件導向程式設計
文章盡量導向中文資料,能力許可下還是看英文資料較好。
Ruby中有個語法,在資料後面加上.class
,可以查資料的類別。
2.7.3 :020 > :a1234.class
=> Symbol
2.7.3 :021 > 1234.class
=> Integer
2.7.3 :022 > "1234".class
=> String #有""或''的就為字串。
2.7.3 :023 > [1, 2, 3, 4].class
=> Array
2.7.3 :024 > (1..4).class
=> Range
2.7.3 :025 > {:a => 1, "b" => 2, c: 3}.class
=> Hash
另外可以用.methods
對類別產生的實體查詢本身有哪些方法。(方法等於怎麼操作這些資料)
2.7.3 :022 > new_array = Array.new
=> []
2.7.3 :023 > new_array.methods
=> [:to_h, :include?, :&, :*, :+, :-, :at, :fetch, :last, :union, :difference, :intersection, :push, :append, :pop, :shift, :unshift, :each_index, :join, :rotate, :rotate!, :sort!, :sort_by!, :collect!, :map!, :select!, :filter!, :keep_if, :values_at, :delete_at,
略....]
#太多了
2.7.3 :024 > new_array.methods.size
=> 192
#192種.
2.7.3 :067 > Array.methods.size
=> 114
#補充:Array原生只有114種方法,new出來的有多78種。可以兩者相減看看多哪些方法
Array.methods - new_array.methods
較特殊的。
2.7.3 :024 > true.class
=> TrueClass
2.7.3 :025 > false.class
=> FalseClass
2.7.3 :026 > nil.class
=> NilClass #null或其他語言可能拼法不同。
布林值
,Ruby沒有這種型別,但是有給予類別,在我個人學習後會比較讓自己去記得Ruby只有類別,沒有型別。
但是資料的確是都有自己的型態沒錯。(記憶體儲存方式)nil
就是空的,會去記,Ruby為了讓你看到空白,所以讓你看到nil
2.7.3 :003 > nil.to_s
=> ""
#真的如果有新手路過看到這個還看不懂,請先略過之後都會說明。
當然Ruby中不只這六種類別,這六種為比較常見的Ruby資料類別而已,初學會以這幾種出發。除了符號這類別可能比較陌生,還有Hash在Ruby叫雜湊外,其他的資料處理方式都與其他程式大同小異。認識資料類別最大目的為,怎麼處理資料,Ruby雖然為強型別語言,但個類別間有很多方法做轉換,甚至有很多同名方法,初學以能越快速掌握越好。而由於網路上大神們的資料已經夠詳細,我將會直接以解題做分享。
Ruby是物件導向程式設計的語言。
無論瞭不瞭解OOP,先知道如果需要處理物件,以變數來指向,會比較便利。
變數與常數簡單一點來想就是,只是一個標籤(名字),拿來指向一個物件,物件於Ruby多指類別的實例,也就是實體,最簡單的實體就是基礎的資料,指向完成後,變數成為了實體(物件)的名字,我們可以將變數拿來操作,不用重複輸入物件(實體)。
例如:x = 123
看起來像x這個變數等於123
事實上x這變數指向123
=
是個指向方法,不是等於。
例如:
2.7.3 :091 > num = 202120212021
=> 202120212021
2.7.3 :092 > num / 2021
=> 100010001
2.7.3 :093 > num * 2021
=> 408484948494441
2.7.3 :094 > num - 2021
=> 202120210000
以及以後會常看到的
2.7.3 :099 > num = 10
=> 10
2.7.3 :100 > num
=> 10
2.7.3 :101 > num = num - 5
=> 5
2.7.3 :102 > num
=> 5
2.7.3 :103 > num = num * 5
=> 25
2.7.3 :104 > num
=> 25
#賦予運算,下面會稍微提到為何可以如此操作。
變數為開頭小寫英文的數字加組合,如abc
、a123
、a1b1
、aAaa
,除了_
不要有計算符號於內,如a+c
、a@a
、x123^
這些都會造成錯誤。
常數為開頭大寫英文的數字加組合,其餘與變數相同,如Abc
、A_BC
。
因此於Ruby,除開頭大小寫外,使用Ruby者多以常數指向不輕易變動之資料,若要變動則會有警告提示(而已),所以類別與模組強制使用常數來命名。
2.7.3 :005 > num = 1
=> 1
2.7.3 :006 > num = 2
=> 2
2.7.3 :007 > num = 3
=> 3
2.7.3 :008 > Num = 1
=> 1
2.7.3 :009 > Num = 2
(irb):9: warning: already initialized constant Num
(irb):8: warning: previous definition of Num was here
=> 2
#對,就警告而已,我們是大人了,不要做被警告的事就好。
2.7.3 :012 > def Add(num1, num2)
2.7.3 :013 > num1 + num2
2.7.3 :014 > end
=> :Add #方法用變數,這是錯誤示範,強調Ruby的風格較自由,但Ruby使用者不會這麼做。
2.7.3 :015 > class error
2.7.3 :016 > p "錯誤"
2.7.3 :017 > end
SyntaxError ((irb):15: class/module name must be CONSTANT)
class error
^~~~~ #沒有例外
#類別只能用常數。
保持可閱讀性,寧可越詳細越好,也盡量不要有x
、a
、xy
、這種無意義的魔法編碼。請讓一年後的自己還知道自己了寫什麼
使用者多以蛇式命名、first_number
。
保留變數:很多,記會噴錯就代表不能用,例如不可能會有nil = 123
,if = 123
。
會於進入Rails前說明。
我們先了解怎麼用。
什麼是符號?
符號指:
加上變數
。變數前面掛上:
就會成為符號。
2.7.3 :019 > :abc
=> :abc
2.7.3 :010 > :acb.class
=> Symbol
#不是:是符號,而是:abc是一個符號。
#不是指+,-,*,%這些已經被包裝成方法的運算式,也不是指@, #, $這些。
符號常見於Hash中當做Key指向Value,{:a => 1}
,或將方法名稱標記,等於是一個固定住的物件。
2.7.3 :001 > def some_method
2.7.3 :002 > p "do something"
2.7.3 :003 > end
=> :some_method
# 運用到Rails上會看到下面類似使用方式。
after_save :some_method
# 在實體存擋後執行一個方法。
#我們可以隨意將變數隨意拿來使用
2.7.3 :004 > some_method = 123
=> 123
2.7.3 :005 > some_method = 1234
=> 1234
#但符號不能
2.7.3 :006 > :some_method = 123
SyntaxError ((irb):6: syntax error, unexpected '=', expecting end-of-input)
:some_method = 123
^
#即使變數一直改指定,剛剛def的方法不會受影響。
2.7.3 :007 > some_method()
"do_something"
=> "do_something"
some_method這串英文只是變數,可以指向任何資料,也可以當方法的名稱。
:some_method等於是有個方法(物件)出現了,給他除了變數外,加固給他一個特別的名字。
Hash中,字串也可以當Key。
2.7.3 :025 > {:a => 1, "b" => 2, c: 3}.class
=> Hash
#上面寫法錯誤示範,下篇介紹Hash會說明。
但符號的記憶體位置是固定的,字串不是。
2.7.3 :014 > :some_method.object_id
=> 2041948
2.7.3 :015 > :some_method.object_id
=> 2041948
2.7.3 :016 > "some_method".object_id
=> 180
2.7.3 :017 > "some_method".object_id
=> 200
2.7.3 :018 > "some_method".object_id
=> 220
2.7.3 :019 > "some_method".object_id
#也所以Rails還是常見。
after_save :some_method
#下面也是可以。
after_save "some_method"
符號,字串,變數三者是不同的。
符號,字串為類別的一種,:symbol
與"string"
則已經是實體(物件),變數只是指向物件(實體)的標籤。
符號,字串都可以當KEY指向物件,而由於記憶體固定,處理符號會比處理字串稍快,但字串本身具有方法就多,選用上可視狀況更改。
num = num + 1
符號與字串就不能這樣操作,在指向(=)這個方法前面只能是變數。
那 = 這方法是前面先執行還是後面先執行?
2.7.3 :002 > x.class
NameError (undefined local variable or method `x' for main:Object)
#x是變數,不是任何類別
2.7.3 :003 > x = z
NameError (undefined local variable or method `z' for main:Object)
#z是變數,但沒指向任何物件。
2.7.3 :004 > x.class
=> NilClass
#但是剛剛的x已經變成一種nil類別的。但還是沒有意義喔nil於Ruby就是nil。
2.7.3 :005 > z.class
NameError (undefined local variable or method `z' for main:Object)
#z卻沒有
我會先回答,= 將前面變數預設成nilcalss,= 後面是運算式(或方法或物件)的回傳值。答非所問!?
2.7.3 :019 > 1.class
=> Integer
2.7.3 :020 > 0101.class
=> Integer #2進制
2.7.3 :030 > "32".to_i.class #=> 32
=> Integer
2.7.3 :025 > x = 50
=> 50
2.7.3 :026 > x.class
=> Integer #變數指向什麼資料,變數則表示什麼類別。
2.7.3 :027 > arr = [1, 2, 4, 5]
=> [1, 2, 4, 5]
2.7.3 :028 > y = arr.size
=> 4
2.7.3 :029 > y.class
=> Integer
2.7.3 :031 > (x - y).class
=> Integer #運算式,方法結果為數字,類別則為數字。
處理數字類別時,理所當然的對數學越了解越吃香,但數學不強,至少要認識基本運算符號到底求的是什麼。
2 * 3 #=>6 ,一個*是乘法
2 ** 3 #=>8 ,兩個**是次方
10 / 2 #=>5 ,/ 是求商
10 % 2 #=>0 ,% 是求餘
#賦予運算 +=, /=, *=等
#判斷 ==, !=, <, >等。
2.7.3 :032 > 1.0.class
=> Float
2.7.3 :033 > 1.0342342343.class
=> Float
2.7.3 :034 > y = 7 / 3
=> 2
2.7.3 :035 > y.class
=> Integer
2.7.3 :036 > y = 7 / 3.0
=> 2.3333333333333335
2.7.3 :037 > y.class
=> Float
初期最重要一點,Integer與Float運算結果為Float。
這三題剛好都可以用單純數學來解,所以一起說了避免我之後偷懶拿來混天數。
另外預防針:由於菜鳥,時間空間複雜度我不會去討論,能解優先。
題目連結Power of Two:https://leetcode.com/problems/power-of-two/
題目連結Power of Three:https://leetcode.com/problems/power-of-three/
題目連結:Power of Four:https://leetcode.com/problems/power-of-four/
三題分別求Input是否為2, 3, 4的次方數。
三題都可以跑迴圈
#0次方都是等於1,所以1一定對。
return true if n == 1
#設定自乘次數起始值
power_number = 1 #設1是因為0次方是1
#Input都一定是2或3或4,自己乘自己N次後會變成的數。請記得我們在三題一起解..
while power_number < n
power_number *= 2 #或3 , 4
end
power_number == n
整理一下
def is_power_of_?(n) # ? = two, three, four
return true if n == 1
power_number = 1 #設1是因為0次方是1
while power_number < n
power_number *= ? #?請自行換2,3,4
end
power_number == n
end
而數學比較好的人,可能會了解,2或3的(n次方數大的)除以2或3的(n次方數小的),一定沒有餘數這件事。
2.7.3 :036 > (2**100)%(2**50)
=> 0
2.7.3 :037 > (2**100)%(2**99)
=> 0
2.7.3 :038 > (2**100)%(2**4)
=> 0
2.7.3 :039 > (2**100)%(2**0)
=> 0
所以可以更快的想到另一種解答。
#2的,為何用2的32次方,因為題目提示有說 n < 2**32
n <= 0 ? false : (2**32 % n == 0)
#3的,1162261467是3的19次方,20次方就超過 2**32了
n > 0 && 1162261467 % n == 0
2用三元運算子寫,3用兩個判斷句合併,寫法不同目的相同。
另外,4的確也符合(大的N次方)%(小的N次方)是餘零這件事,但是由於4 = 2*2這件事,所以不會直接拿來解,但可以利用
(4**n - 1) % 3 == 0
這個邏輯來解喔。
本日結束,明日會用其他例題說明字串,範圍,陣列,雜湊。
整理今天提到。
1.變數與常數差異。
2.符號、變數、字串三者差異。
3.資料基本型態:Integer
4.leetcode:power_of_two..four